home *** CD-ROM | disk | FTP | other *** search
/ Nebula 2 / Nebula Two.iso / SourceCode / MiscKit1.7.1 / MiscKit / Temp / MiscPickList / MiscPickList.m < prev    next >
Text File  |  1995-04-12  |  8KB  |  333 lines

  1. //
  2. //    MiscPickList.m -- Pick List
  3. //        Written by Don Yacktman Copyright (c) 1994 by Don Yacktman.
  4. //                Version 0.1.  All rights reserved.
  5. //
  6. //        This notice may not be removed from this source code.
  7. //
  8. //    This object is included in the MiscKit by permission from the author
  9. //    and its use is governed by the MiscKit license, found in the file
  10. //    "LICENSE.rtf" in the MiscKit distribution.  Please refer to that file
  11. //    for a list of all applicable permissions and restrictions.
  12. //    
  13.  
  14. #import "MiscPickList.h"
  15. #import <sys/param.h>
  16.  
  17. #define MISC_PickListExtension "picklist"
  18. static MiscDictionary *availableLists = nil;
  19.  
  20. @interface MiscPickList(private)
  21.  
  22. - _enableButtons:(BOOL)flag;
  23. - _updateBrowser;
  24.  
  25. @end
  26.  
  27. @implementation MiscPickList(private)
  28.  
  29. - _enableButtons:(BOOL)flag
  30. {
  31.     [modifyButton setEnabled:flag];
  32.     [addButton setEnabled:flag];
  33.     return self;
  34. }
  35.  
  36. - _updateBrowser
  37. {
  38.     // adds/removes the items in the browser as necessary
  39.     int i, cnt;
  40.     [self loadNibIfNeeded];
  41.     cnt = [sortedKeys count];
  42.     [browser renewRows:cnt cols:1];
  43.     for (i=0; i<cnt; i++) {
  44.         id newCell = [browser cellAt:i :0];
  45.         [newCell setTag:i];
  46.         [newCell setTitle:[[sortedKeys objectAt:i] stringValue]];
  47.     }
  48.     [[browser sizeToCells] display];
  49.     return self;
  50. }
  51.  
  52. @end
  53.  
  54.  
  55. @implementation MiscPickList
  56.  
  57. + findPickListNamed:(MiscString *)aName
  58. {
  59.     if (!availableLists) {
  60.         availableLists = [[MiscDictionary alloc] init];
  61.     }
  62.     if ([availableLists isKey:aName]) {
  63.         return [availableLists valueForKey:aName];
  64.     } else {
  65.         MiscPickList *theList = [[self alloc] initForListNamed:aName];
  66.         [availableLists insertKey:aName value:theList];
  67.         return theList;
  68.     }
  69.     return nil;
  70. }
  71.  
  72. + (MiscString *)pickListExtension
  73. {
  74.     static id theExtension = nil;
  75.     if (!theExtension)
  76.         theExtension = [MiscString newWithString:MISC_PickListExtension];
  77.     return theExtension;
  78. }
  79.  
  80. + (MiscString *)fileNameForPickListNamed:(MiscString *)aName
  81. {
  82.     char path[MAXPATHLEN+1];
  83.     char *file; MiscString *fileName;
  84.  
  85.     if ([[NXBundle mainBundle]  getPath:path
  86.             forResource:[aName stringValue]
  87.             ofType:[[self pickListExtension] stringValue]])
  88.         return [MiscString newWithString:path];
  89.     // Couldn't find it in the app bundle, so we'll check the
  90.     // various libraries and see what we can find...
  91.     if (![MiscFileFinder findFileTypeNamed: "PickLists"]) {
  92.         [[MiscFileFinder alloc] initName:"PickLists"
  93.             defaultPath:
  94.             "~/Library/PickLists:/Library/PickLists:/LocalLibrary/PickLists"
  95.             pathVariable:"PICKLISTPATH" mode:R_OK];
  96.     }
  97.     fileName = [[MiscString alloc] initFromFormat:"%s.%s",
  98.             [aName stringValue], [[self pickListExtension] stringValue]];
  99.     file = [[MiscFileFinder findFileTypeNamed:"PickLists"]
  100.             fullPathForFile:[fileName stringValue]];
  101.     [fileName free];
  102.     if (file) return [MiscString newWithString:file];
  103.     return nil; // couldn't find it.
  104. }
  105.  
  106. - init
  107. {
  108. //    return [self error:"Don't call MiscPickList's -init method!"];
  109.     return [self initForListNamed:[MiscString newWithString:"Default"]];
  110. }
  111.  
  112. - free
  113. {
  114.     [itemList freeObjects];
  115.     [itemList free];
  116.     [sortedKeys freeObjects];
  117.     [sortedKeys free];
  118.     [listPath free];
  119.     [listName free];
  120.     return [super free];
  121. }
  122.  
  123. - initForListNamed:(MiscString *)aName
  124. {
  125.     [super init];
  126.     autoSave = YES;
  127.     sortedKeys = [[List alloc] init];
  128.     itemList = nil;
  129.     [self loadItemList:nil name:aName];
  130.     return self;
  131. }
  132.  
  133. - loadItemList:(MiscString *)aPath name:(MiscString *)aName
  134. {
  135.     if (listName) [listName free];
  136.     listName = [aName copy];
  137.     if (listPath) [listPath free];
  138.     listPath = [aPath copy];
  139.     if (!listPath) {
  140.         listPath = [[self class] fileNameForPickListNamed:aName];
  141.     }
  142.     [self reloadItemList];
  143.     return self;
  144. }
  145.  
  146. - reloadItemList;
  147. {
  148.     if (itemList) {
  149.         [itemList freeObjects];
  150.         [itemList free];
  151.     }
  152.     itemList = MiscParseTableFile(listPath);
  153.     [sortedKeys freeObjects];
  154.     [sortedKeys empty];
  155.     {
  156.         void *k, *v;
  157.         NXHashState hs = [itemList initState];
  158.         while ([itemList nextState:&hs key:&k value:&v]) {
  159.             [sortedKeys addObject:[(id)k copy]];
  160.         }
  161.         [sortedKeys miscStringSort];
  162.     }
  163.     changed = NO;
  164.     return self;
  165. }
  166.  
  167. - saveList { return [self saveListToPath:listPath]; }
  168. - saveListToPath:(MiscString *)aPath
  169. {
  170.     // ***** If we can't save to a global list, then we should try to
  171.     // save to a list in the user's ~Library directory.
  172.     MiscWriteTableFile(aPath, itemList);
  173.     changed = NO;
  174.     return self;
  175. }
  176.  
  177. - popUp:sender
  178. {
  179.     [self _updateBrowser];
  180.     [browser selectCellAt:0 :0];
  181.     [browser scrollCellToVisible:0 :0];
  182.     [entryText takeStringValueFrom:[self selectedKey]];
  183.     [[self window] setTitle:[listName stringValue]];
  184.     [[self window] makeKeyAndOrderFront:self];
  185.     // ***** probably want to position the window near the text field...
  186.     return self;
  187. }
  188.  
  189. - popUpForTextPal:aTextField
  190. {
  191.     [self setTextPal:aTextField];
  192.     return [self popUp:nil];
  193. }
  194.  
  195. - doEntry:sender
  196. {
  197.     [entryText takeStringValueFrom:[self selectedKey]];
  198.     [textPal takeStringValueFrom:[itemList valueForKey:[self selectedKey]]];
  199.     return self;
  200. }
  201.  
  202. - finishEntry:sender
  203. {
  204.     [self doEntry:sender];
  205.     [[self window] orderOut:self];
  206.     return self;
  207. }
  208.  
  209. - addItem:sender
  210. {
  211.     id theString = [MiscString new];
  212.     if (![entryText respondsTo:@selector(stringValue)]) return nil;
  213.     [theString takeStringValueFrom:entryText];
  214.     [self addItemToList:theString value:theString];
  215.     [self _enableButtons:NO];
  216.     return self;
  217. }
  218.  
  219. - modifyItem:sender
  220. {
  221.     // Take the selected key, delete it, and then do an add.
  222.     [[self window] disableDisplay];
  223.     [[self window] disableFlushWindow];
  224.     [self removeItemFromList:[self selectedKey]];
  225.     [self addItem:sender];
  226.     [self _enableButtons:NO];
  227.     [[self window] reenableDisplay];
  228.     [[self window] reenableFlushWindow];
  229.     [[self window] display];
  230.     return self;
  231. }
  232.  
  233. - addItemToList:(MiscString *)anItem
  234. {
  235.     [self addItemToList:anItem value:anItem];
  236.     return self;
  237. }
  238.  
  239. - addItemToList:(MiscString *)anItem value:(MiscString *)aValue
  240. {
  241.     BOOL haveIt = ([itemList isKey:anItem] ? YES : NO);
  242.  
  243.     // return if already have key _and_ it has identical value:
  244.     if (haveIt) {
  245.         id existingValue = [itemList valueForKey:anItem];
  246.         if ([existingValue isEqual:aValue]) return nil; // no changes...
  247.     }
  248.     [[self window] disableDisplay];
  249.     [[self window] disableFlushWindow];
  250.     // add the item to the list, update the browser
  251.     [itemList insertKey:anItem value:aValue];
  252.     if (!haveIt) {
  253.         [sortedKeys addObject:anItem];
  254.         [sortedKeys miscStringSort];
  255.         [self _updateBrowser]; // browser displays keys, we only update
  256.             // if we didn't have the key before.
  257.         [self selectKey:anItem];
  258.     }
  259.     changed = YES;
  260.     if (autoSave) [self saveList];
  261.     [[self window] reenableDisplay];
  262.     [[self window] reenableFlushWindow];
  263.     [[self window] display];
  264.     return self;
  265. }
  266.  
  267. - removeItemFromList:(MiscString *)anItem
  268. {
  269.     int i;
  270.  
  271.     if (![itemList isKey:anItem]) return nil;
  272.     [itemList removeKey:anItem];
  273.     for (i=0; i<[sortedKeys count]; i++) {
  274.         if ([[sortedKeys objectAt:i] isEqual:anItem]) {
  275.             [sortedKeys removeObjectAt:i];
  276.             changed = YES;
  277.             [self _updateBrowser];
  278.             if (autoSave) [self saveList];
  279.             return self;
  280.         }
  281.     }
  282.     return nil;
  283. }
  284.  
  285. - (MiscDictionary *)itemList { return itemList; }
  286. - (BOOL)isDirty { return changed; }
  287. - (MiscString *)listPath { return listPath; }
  288. - (MiscString *)listName { return listName; }
  289. - (BOOL)autoSave { return autoSave; }
  290. - setAutoSave:(BOOL)flag { autoSave = flag; return self; }
  291. - browser { return browser; }
  292. - entryText { return entryText; }
  293. - textPal { return textPal; }
  294. - setBrowser:anObject { browser = anObject; return self; }
  295. - setEntryText:anObject { entryText = anObject; return self; }
  296. - setTextPal:anObject { textPal = anObject; return self; }
  297.  
  298. - nibDidLoad
  299. {
  300.     [browser setDoubleAction:@selector(finishEntry:)];
  301.     return [super nibDidLoad];
  302. }
  303.  
  304. - (BOOL)textWillChange:textObject
  305. {
  306.     [self _enableButtons:YES];
  307.     return NO;
  308. }
  309.  
  310. - (MiscString *)selectedKey
  311. {
  312.     static id aString = nil;
  313.     if (!aString) aString = [MiscString new];
  314.     [aString setStringValue:[[browser selectedCell] title]];
  315.     return aString;
  316. }
  317.  
  318. - selectKey:(MiscString *)aKey
  319. {
  320.     int i;
  321.     for (i=0; i<[sortedKeys count]; i++) {
  322.         if ([aKey isEqual:[sortedKeys objectAt:i]]) {
  323.             [browser selectCellAt:i :0];
  324.             [browser scrollCellToVisible:i :0];
  325.             [self doEntry:browser]; // as if they clicked here...
  326.             return self;
  327.         }
  328.     }
  329.     return nil;
  330. }
  331.  
  332. @end
  333.